package org.springframework.zp.transaction.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;

@Configuration
// 2、开启注解支撑
@EnableTransactionManagement
@ComponentScan("org.springframework.zp.transaction")
public class App {

	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dataSource());
	}

	@Bean
	public DataSource dataSource() {
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setPassword("root");
		dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-yuanma?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC");
		dataSource.setUsername("root");
		return dataSource;
	}

	/**
	 * 1、注入 基于 数据库连接的事务管理器 PlatformTransactionManager
	 *
	 * @return
	 */
	@Bean
	public PlatformTransactionManager transactionManager() {
		/**
		 * 事务管理器
		 *  这里面设置了 默认支持嵌套事务  ，所以该类就需要从头到尾好好看下
		 *  比如 {@link DataSourceTransactionManager#doBegin(Object, TransactionDefinition)} 方法中使用  ThreadLocal  将当前线程 与 数据库连接进行绑定
		 */
		DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
		// 设置数据源信息
		dataSourceTransactionManager.setDataSource(dataSource());
		return dataSourceTransactionManager;
	}

	/**
	 * 注入 TransactionTemplate bean
	 *
	 *
	 * @return
	 */
	@Bean
	public TransactionTemplate transactionTemplate() {
		/**
		 * 事务模板 老规矩，这个类中的方法 也需要从头到尾好好看下
		 * 比如 {@link TransactionTemplate#execute(TransactionCallback)} 该方法中就针对事务进行了 代理操作，
		 * 默认情况下 针对了 所有异常都进行了处理操作
		 */
		TransactionTemplate transactionTemplate = new TransactionTemplate();
		// 注入事务管理器
		transactionTemplate.setTransactionManager(transactionManager());
		return transactionTemplate;
	}


}
